package  com.ai_daily.aitiantian.api

import android.annotation.SuppressLint
import com.ai_daily.aitiantian.BuildConfig
import com.ai_daily.aitiantian.base.BaseApp
import com.ai_daily.aitiantian.util.NetUtil
import com.google.firebase.perf.FirebasePerformance
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import java.io.IOException
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.net.ssl.HttpsURLConnection
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509TrustManager
import com.ai_daily.aitiantian.core.recog.listener.TimeRecorder

/**
 * OKHttp
 *
 */
class OkHttpModule {

    fun provideOkHttp(): OkHttpClient = getBaseBuilder()
        .addInterceptor(HeadInterceptor())
        .addInterceptor(provideLoggingInterceptor())
//        .addInterceptor(NetworkMetricsInterceptor())
        .build()

    fun provideDownOkHttp(startPoint: Long, listener: IDownloadListener): OkHttpClient =
        getBaseBuilder()
            .addInterceptor(HeadInterceptor())
            .addInterceptor(provideLoggingInterceptor())
            .addInterceptor(provideDownloadInterceptor(startPoint, listener))
            .build()

    fun provideStreamOkHttp(): OkHttpClient = getBaseBuilder()
        .callTimeout(600, TimeUnit.SECONDS)
        .addInterceptor(HeadInterceptor())
        .addInterceptor(provideLoggingInterceptor())
//        .addInterceptor(NetworkMetricsInterceptor())
        .build()

    private fun getBaseBuilder(): OkHttpClient.Builder {
        val loggingInterceptor = HttpLoggingInterceptor()
        if (BuildConfig.DEBUG) {
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
        } else {
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE)
        }
        val timeout = 120L
        return OkHttpClient.Builder()
            .readTimeout(5, TimeUnit.MINUTES)
            .writeTimeout(5, TimeUnit.MINUTES)
            .connectTimeout(timeout, TimeUnit.SECONDS)
            .addInterceptor(loggingInterceptor)
            .sslSocketFactory(getSSLSocketFactory(), getTrustManager()[0])
            .connectionPool(ConnectionPool(10, 10, TimeUnit.MINUTES))
    }

    private fun getTrustManager(): Array<X509TrustManager> {
        return arrayOf(object : X509TrustManager {
            @SuppressLint("TrustAllX509TrustManager")
            @Throws(CertificateException::class)
            override fun checkClientTrusted(x509Certificates: Array<X509Certificate>, s: String) {
            }

            @SuppressLint("TrustAllX509TrustManager")
            @Throws(CertificateException::class)
            override fun checkServerTrusted(x509Certificates: Array<X509Certificate>, s: String) {
                x509Certificates[0].checkValidity()
            }

            override fun getAcceptedIssuers(): Array<X509Certificate> {
                return arrayOf()
            }
        })
    }

    private val verifyHostName = arrayOf<String>()
    private fun getSSLSocketFactory(): SSLSocketFactory {
        val ssContext: SSLContext = SSLContext.getInstance("TLS")
        ssContext.init(null, getTrustManager(), SecureRandom())
        HttpsURLConnection.setDefaultSSLSocketFactory(ssContext.socketFactory)
        HttpsURLConnection.setDefaultHostnameVerifier { hostname: String?, _ ->
            if (hostname == null) {
                false
            }
            !verifyHostName.contains(hostname)
        }
        return ssContext.socketFactory
    }

    /**
     * header 拦截器
     */
    class HeadInterceptor : Interceptor {
        @Throws(IOException::class)
        override fun intercept(chain: Interceptor.Chain): Response {
            val headers = Headers.Builder()
                .set("Content-Type", "application/json; charset=utf-8")
//                .set("Device-Id", AppUtils.getDeviceId(BaseApp.getInstance()))
//                .set("User-Agent", AppUtils.getUserAgent(BaseApp.getInstance()))
                .build()
            val request = chain.request()
                .newBuilder()
                .headers(headers)
                .build()
            return chain.proceed(request)
        }
    }

    /**
     * OkHttp 日志拦截器
     */
    private fun provideLoggingInterceptor(): HttpLoggingInterceptor {
        return HttpLoggingInterceptor().apply {
            level = if (BuildConfig.DEBUG) {
                // debug 模式打印全部信息
                HttpLoggingInterceptor.Level.BODY
            } else {
                HttpLoggingInterceptor.Level.NONE // no logs
            }
        }
    }

    /**
     * 下载拦截器，增加断点
     */
    private fun provideDownloadInterceptor(
        startPoint: Long,
        downloadListener: IDownloadListener
    ): Interceptor {
        return Interceptor() {
            val headers = Headers.Builder().set("RANGE", "bytes=$startPoint-").build()
            val request = it.request()
                .newBuilder()
                .headers(headers).build()
            val response = it.proceed(request)
            response.newBuilder().body(
                JDResponseBody(startPoint, response.body, downloadListener)
            ).build()
        }
    }

    val cacheInterceptor = Interceptor { chain: Interceptor.Chain ->
        var request = chain.request()
        request = if (NetUtil.isNetworkAvailable(BaseApp.getInstance())) {
            //有网络时给相应头加上：缓存超时为0小时
            val maxAge = 0
            request.newBuilder()
                .removeHeader("Pragma")
                .header("Content-Type", "application/json; charset=utf-8")
                .header("Cache-Control", "public, max-age=$maxAge")
                .build()
        } else {
            //网络不可用
            request = request.newBuilder()
                .cacheControl(CacheControl.FORCE_CACHE)
                .url(chain.request().url)
                .build()

            //无网络时，在相应头加上：设置缓存超时为4周
            val maxStale = 60 * 60 * 24 * 28
            request.newBuilder()
                .removeHeader("Pragma")
                .header("Content-Type", "application/json; charset=utf-8")
                .header("Cache-Control", "public, only-if-cached, max-stale=$maxStale")
                .build()
        }
        chain.proceed(request)
    }

    private class NetworkMetricsInterceptor : Interceptor {
        override fun intercept(chain: Interceptor.Chain): Response {
            val request = chain.request()
            val metric = FirebasePerformance.getInstance()
                .newHttpMetric(request.url.toString(), request.method)

            try {
                metric.start()
                metric.putAttribute("domain", request.url.host)
                metric.putAttribute("path", request.url.encodedPath)
                metric.putAttribute("api_name", request.url.pathSegments.last())
                val response = chain.proceed(request)
                metric.setHttpResponseCode(response.code)
                
                return response
            } finally {
                metric.stop()
            }
        }
    }
}